/*-------------------------------------------------------------------------
 * drawElements Quality Program Helper Library
 * -------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Debug output utilities.
 *//*--------------------------------------------------------------------*/

#include "qpDebugOut.h"

#include "qpCrashHandler.h" /*!< for QP_USE_SIGNAL_HANDLER */

#include <stdio.h>
#include <stdlib.h>

typedef enum MessageType_e
{
	MESSAGETYPE_INFO	= 0,
	MESSAGETYPE_ERROR,
	MESSAGETYPE_NONFATAL_ERROR,

	MESSAGETYPE_LAST
} MessageType;

static void		printRaw		(MessageType type, const char* msg);
static void		printFmt		(MessageType type, const char* fmt, va_list args);
static void		exitProcess		(void);

void qpPrint (const char* message)
{
	printRaw(MESSAGETYPE_INFO, message);
}

void qpPrintf (const char* format, ...)
{
	va_list args;
	va_start(args, format);
	printFmt(MESSAGETYPE_INFO, format, args);
	va_end(args);
}

void qpPrintErrorf (const char* format, ...)
{
	va_list args;
	va_start(args, format);
	printFmt(MESSAGETYPE_NONFATAL_ERROR, format, args);
	va_end(args);
}

void qpPrintv (const char* format, va_list args)
{
	printFmt(MESSAGETYPE_INFO, format, args);
}

void qpPrintErrorv (const char* format, va_list args)
{
	printFmt(MESSAGETYPE_NONFATAL_ERROR, format, args);
}

void qpDief (const char* format, ...)
{
	va_list args;
	va_start(args, format);
	printFmt(MESSAGETYPE_ERROR, format, args);
	va_end(args);

	exitProcess();
}

void qpDiev (const char* format, va_list args)
{
	printFmt(MESSAGETYPE_ERROR, format, args);
	exitProcess();
}

/* print() implementation. */
#if (DE_OS == DE_OS_ANDROID)

#include <android/log.h>

static android_LogPriority getLogPriority (MessageType type)
{
	switch (type)
	{
		case MESSAGETYPE_INFO:	return ANDROID_LOG_INFO;
		case MESSAGETYPE_ERROR:	return ANDROID_LOG_FATAL;
		default:				return ANDROID_LOG_DEBUG;
	}
}

void printRaw (MessageType type, const char* message)
{
	__android_log_write(getLogPriority(type), "dEQP", message);
}

void printFmt (MessageType type, const char* format, va_list args)
{
	__android_log_vprint(getLogPriority(type), "dEQP", format, args);
}

#else

static FILE* getOutFile (MessageType type)
{
	if (type == MESSAGETYPE_ERROR || type == MESSAGETYPE_NONFATAL_ERROR)
		return stderr;
	else
		return stdout;
}

void printRaw (MessageType type, const char* message)
{
	FILE* out = getOutFile(type);

	if (type == MESSAGETYPE_ERROR)
		fprintf(out, "FATAL ERROR: ");

	fputs(message, out);

	if (type == MESSAGETYPE_ERROR)
	{
		putc('\n', out);
		fflush(out);
	}
}

void printFmt (MessageType type, const char* format, va_list args)
{
	FILE* out = getOutFile(type);

	if (type == MESSAGETYPE_ERROR)
		fprintf(out, "FATAL ERROR: ");

	vfprintf(out, format, args);

	if (type == MESSAGETYPE_ERROR)
	{
		putc('\n', out);
		fflush(out);
	}
}

#endif

/* exitProcess() implementation. */
#if (DE_OS == DE_OS_WIN32)

#define NOMINMAX
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

static void exitProcess (void)
{
	/* Some API implementations register atexit() functions that may hang.
	   By using TerminateProcess() we can avoid calling any potentially hanging exit routines. */
	HANDLE curProc = GetCurrentProcess();
	TerminateProcess(curProc, -1);
}

#else

#if (DE_OS == DE_OS_IOS)
#	include "deThread.h"	/*!< for deSleep() */
#endif

#if defined(QP_USE_SIGNAL_HANDLER)
#	include <signal.h>
#endif

static void exitProcess (void)
{
#if (DE_OS == DE_OS_IOS)
	/* Since tests are in the same process as execserver, we want to give it
	   a chance to stream complete log data before terminating. */
	deSleep(5000);
#endif

#if defined(QP_USE_SIGNAL_HANDLER)
	/* QP_USE_SIGNAL_HANDLER defined, this means this function could have
	   been called from a signal handler. Calling exit() inside a signal
	   handler is not safe. */

	/* Flush all open FILES */
	fflush(DE_NULL);

	/* Kill without calling any _at_exit handlers as those might hang */
	raise(SIGKILL);
#else
	exit(-1);
#endif
}

#endif
